﻿namespace MicroCloud.AspNetCore.Mvc
{
    /// <summary>
    /// MVC模块信息提取器
    /// </summary>
    public class MvcModuleInfoPicker : ModuleInfoPickerBase<Function>
    {
        /// <summary>
        /// 初始化一个MVC模块信息提取器 <see cref="MvcModuleInfoPicker"/> 的新实例
        /// </summary>
        /// <param name="serviceProvider"></param>
        public MvcModuleInfoPicker(IServiceProvider serviceProvider)
            : base(serviceProvider)
        { }

        #region 方法
        /// <summary>
        /// 重写以实现从类型中提取模块信息
        /// </summary>
        /// <param name="type">类型信息</param>
        /// <param name="existPaths">已存在的路径集合</param>
        /// <returns>提取到的模块信息</returns>
        protected override ModuleInfo[] GetModules(Type type, string[] existPaths)
        {
            ModuleInfoAttribute infoAttr = type.GetAttribute<ModuleInfoAttribute>();
            if (infoAttr == null)
            {
                return Array.Empty<ModuleInfo>();
            }
            //设置模块信息
            ModuleInfo info = new()
            {
                Code = infoAttr.Code ?? type.Name.Replace("Controller", ""),
                Name = infoAttr.Name ?? GetName(type),
                OrderNo = infoAttr.OrderNo.ToDecimal(),
                Position = GetPosition(type, infoAttr.Position),
                PositionName = infoAttr.PositionName
            };
            List<ModuleInfo> infos = new() { info };
            //获取并设置中间分类模块
            if (infoAttr.Position != null)
            {
                info = new ModuleInfo()
                {
                    Code = infoAttr.Position,
                    Name = infoAttr.PositionName ?? infoAttr.Position,
                    Position = GetPosition(type, null)
                };
                if (!existPaths.Contains($"{info.Position}.{info.Code}"))
                {
                    infos.Insert(0, info);
                }
            }
            //获取区域模块
            string moduleCode = "", moduleName = "";
            AreaInfoAttribute areaInfo = type.GetAttribute<AreaInfoAttribute>();
            if (areaInfo != null)
            {
                moduleCode = areaInfo.RouteValue;
                moduleName = areaInfo.Display ?? moduleCode;
            }
            else
            {
                AreaAttribute areaAttr = type.GetAttribute<AreaAttribute>();
                //code = areaAttr?.RouteValue ?? "Site";
                //DisplayNameAttribute display = type.GetAttribute<DisplayNameAttribute>();
                //name = display?.DisplayName ?? code;

                if (areaAttr != null)
                {
                    //code = areaAttr?.RouteValue ?? "Site";
                    moduleCode = areaInfo.RouteValue;
                    DisplayNameAttribute display = type.GetAttribute<DisplayNameAttribute>();
                    moduleName = display?.DisplayName ?? moduleCode;
                }
                else
                {
                    var displayAttr = type.GetAttribute<DisplayInfoAttribute>();
                    if (displayAttr != null)
                    {
                        moduleCode = displayAttr.Value;
                        moduleName = displayAttr.Name;
                    }
                    //else
                    //{
                    //    moduleCode = "Site";
                    //    moduleName = "网站";
                    //}
                }
            }
            if (!moduleCode.IsMissing())
            {
                moduleName = moduleName.IsMissing() ? moduleCode : moduleName;
                info = new ModuleInfo()
                {
                    Code = moduleCode,
                    Name = moduleName,
                    Position = "Root",
                    PositionName = moduleName
                };
                if (!existPaths.Contains($"{info.Position}.{info.Code}"))
                {
                    infos.Insert(0, info);
                }
            }

            return infos.ToArray();
        }

        /// <summary>
        /// 重写以实现从方法信息中提取模块信息
        /// </summary>
        /// <param name="method">方法信息</param>
        /// <param name="typeInfo">所在类型模块信息</param>
        /// <param name="index">序号</param>
        /// <returns>提取到的模块信息</returns>
        protected override ModuleInfo GetModule(MethodInfo method, ModuleInfo typeInfo, int index)
        {
            ModuleInfoAttribute infoAttr = method.GetAttribute<ModuleInfoAttribute>();
            if (infoAttr == null)
            {
                return null;
            }
            ModuleInfo info = new()
            {
                Name = infoAttr.Name ?? method.GetDescription() ?? method.Name,
                Code = infoAttr.Code ?? method.Name,
                OrderNo = infoAttr.OrderNo > 0 ? infoAttr.OrderNo.ToDecimal() : index + 1,
            };
            string controller = method.DeclaringType?.Name.Replace("ControllerBase", string.Empty).Replace("Controller", string.Empty);
            info.Position = typeInfo.FullCode.IsMissing() ? $"{typeInfo.Position}.{controller}" : typeInfo.FullCode;
            //依赖的功能
            string area = method.DeclaringType.GetAttribute<AreaAttribute>()?.RouteValue;
            List<IFunction> dependOnFunctions =
            [
                FunctionHandler.GetFunction(area, controller, method.Name)
            ];
            DependOnFunctionAttribute[] dependOnAttrs = method.GetAttributes<DependOnFunctionAttribute>();
            foreach (DependOnFunctionAttribute dependOnAttr in dependOnAttrs)
            {
                //string dependArea = dependOnAttr.Area == null ? area : dependOnAttr.Area == string.Empty ? null : dependOnAttr.Area;
                string dependArea = dependOnAttr.Area.IsNullOrEmpty() ? area : dependOnAttr.Area;
                string dependController = dependOnAttr.Controller?.Replace("Controller", string.Empty) ?? controller;
                IFunction function = FunctionHandler.GetFunction(dependArea, dependController, dependOnAttr.Action);
                if (function == null)
                {
                    var areaName = area.IsMissing() ? "" : $"{area}/";
                    var controllerName = controller.IsMissing() ? "" : $"{controller}/";
                    var dependAreaName = dependArea.IsMissing() ? "" : $"{dependArea}/";
                    var dependControllerName = dependController.IsMissing() ? "" : $"{dependController}/";
                    var errorMsg = $"功能 {areaName}{controllerName}{method.Name} 的依赖功能 {dependAreaName}{dependControllerName}{dependOnAttr.Action} 无法找到";
                    throw new Exception(errorMsg);
                }
                dependOnFunctions.Add(function);
            }
            info.DependOnFunctions = dependOnFunctions.ToArray();

            return info;
        }

        #endregion

        #region 私有静态方法
        /// <summary>
        /// 获取名称
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static string GetName(Type type)
        {
            string name = type.GetDescription();
            if (name == null)
            {
                return type.Name.Replace("Controller", "");
            }
            if (name.Contains('-'))
            {
                name = name.Split('-').Last();
            }
            return name;
        }
        
        /// <summary>
        /// 获取位置
        /// </summary>
        /// <param name="type">类型信息</param>
        /// <param name="attrPosition">模块位置</param>
        /// <returns></returns>
        private static string GetPosition(Type type, string attrPosition)
        {
            string area = type.GetAttribute<AreaAttribute>()?.RouteValue;
            if (area == null)
            {
                //无区域，判断是否存在DisplayInfoAttribute属性，如果存在，从中取Value值作为位置，否则默认
                var displayAttr = type.GetAttribute<DisplayInfoAttribute>();
                if (displayAttr != null)
                {
                    return attrPosition == null ? $"Root.{displayAttr.Value}" : $"Root.{displayAttr.Value}.{attrPosition}";
                }

                //无区域，使用Root位置
                return attrPosition == null ? $"Root" : $"Root.{attrPosition}";
            }
            return attrPosition == null ? $"Root.{area}" : $"Root.{area}.{attrPosition}";
        }

        #endregion

    }

}